home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 1 / PC Actual CD 01.iso / f1 / tutorc.arj / EJEMCPP.DAT < prev    next >
Encoding:
Text File  |  1993-05-04  |  68.4 KB  |  2,699 lines

  1. ;
  2. ; EJEMPLOS DEL LENGUAJE CPP
  3. ;
  4.  
  5. ; LECCION 1
  6. begin
  7. begine ""
  8. #include <stdio.h>
  9. #include <conio.h>
  10.  
  11. void main (void)
  12. {
  13.   puts ("Estas líneas están escritas por un programa C.");
  14.   puts ("Por consiguiente, también están escritas por un programa C++.");
  15.   puts ("Al ser el C++ una extensión del C, todo programa C es también programa C++.");
  16.   getch ();
  17. }
  18. ende
  19. end
  20.  
  21. ; LECCION 2
  22. begin
  23. begine " ORDENACION RAPIDA "
  24. /*
  25.   En este programa se realiza la ordenación creciente de un vector de números
  26.   en coma flotante por el método quicksort (ordenación rápida).
  27.  
  28.   La función principal general aleatoriamente 200 números de tipo float, los
  29.   ordena llamando a la función quick_sort() y por último los visualiza.
  30.  
  31.   La ordenación rápida se basa en la idea de las particiones. El procedimiento
  32.   general es seleccionar un valor pivote y entonces dividir el array en dos
  33.   partes. En un lado todos los elementos mayores o iguales al valor de partición
  34.   y en otro todos los elementos menores que el valor. Este proceso se repite
  35.   en cada parte restante hasta que el array está ordenado.
  36.  
  37.   Este programa utiliza las siguientes mejoras del C++ respecto al C:
  38.   - Nuevo estilo de comentario (//): // Quicksort (Ordenación rápida). Un ...
  39.   - Nuevo flujo de salida estándar (cout): cout << "Memoria insuficiente.\n";
  40.   - Funciones en línea (inline): inline void inicializar_numeros_aleatorios (void);
  41.   - Nuevos operadores de gestión de memoria dinámica (new y delete): delete datos;
  42.   - Conversión de tipo explícita mediante notación funcional: unsigned (time (NULL))
  43.   - Parámetros por referencia en las funciones: operador &: void intercambiar (float& valor1, float& valor2);
  44.   - Declaración en cualquier lugar: for (register int i = 0; ...
  45. */
  46.  
  47. // Quicksort (Ordenación rápida). Un algoritmo desarrollado por C. A. R. Hoare
  48.  
  49. #include <iostream.h> // cout, << sobrecargado
  50. #include <stdlib.h>   // srad(), rand(), NULL
  51. #include <time.h>     // time()
  52. #include <conio.h>    // getch()
  53.  
  54. // Inicializa el generador de números aleatorios.
  55. inline void inicializar_numeros_aleatorios (void)
  56. {
  57.   srand (unsigned (time (NULL)));
  58. }
  59.  
  60. // Devuelve un valor aleatorio entre 1 y num_max.
  61. inline unsigned aleatorio (unsigned num_max)
  62. {
  63.   return (rand () % num_max + 1);
  64. }
  65.  
  66. void main (void)
  67. {
  68.   void quick_sort (float *punt_bajo, float *punt_alto);
  69.   void visualizar_datos (float *dat, const int tam);
  70.   float *datos;
  71.   const int tamanio = 200;
  72.   const unsigned num_aleat_max = 10000;
  73.  
  74.   if ((datos = new float[tamanio]) == 0)
  75.     cout << "Memoria insuficiente.\n";
  76.   else
  77.     {
  78.       inicializar_numeros_aleatorios ();
  79.       for (register int i = 0; i < tamanio; i++)
  80.         *(datos + i) = float (aleatorio (num_aleat_max)) / aleatorio (num_aleat_max);
  81.       quick_sort (datos, datos + tamanio - 1);
  82.       visualizar_datos (datos, tamanio);
  83.       delete datos;
  84.     }
  85.   getch ();
  86. }
  87.  
  88. void quick_sort (float *punt_bajo, float *punt_alto)
  89. {
  90.   float *punt_pivote;
  91.   float *particion (float *punt_bajo, float *punt_alto);
  92.  
  93.   if (punt_bajo < punt_alto)
  94.     {
  95.       punt_pivote = particion (punt_bajo, punt_alto);
  96.       quick_sort (punt_bajo, punt_pivote - 1);
  97.       quick_sort (punt_pivote, punt_alto);
  98.     }
  99. }
  100.  
  101. float *particion (float *punt_bajo, float *punt_alto)
  102. {
  103.   void intercambiar (float& valor1, float& valor2);
  104.   float pivote = *(punt_bajo + (punt_alto - punt_bajo) / 2);
  105.  
  106.   /*
  107.     A la terminación de este bucle, el valor de todos los elementos a la
  108.     izquierda del pivote serán menores que el valor del elemento del pivote,
  109.     y todos los elementos a la derecha del pivote serán mayores que el valor
  110.     del elemento del pivote.
  111.   */
  112.   while (punt_bajo <= punt_alto)
  113.     {
  114.       // Busca un valor en la parte baja del array mayor que el pivote
  115.       while (*punt_bajo < pivote)
  116.         punt_bajo++;
  117.       // Busca un valor en la parte alta del array menor que el pivote
  118.       while (*punt_alto > pivote)
  119.         punt_alto--;
  120.       if (punt_bajo <= punt_alto)
  121.         intercambiar (*punt_bajo++, *punt_alto--);
  122.     }
  123.   return punt_bajo;
  124. }
  125.  
  126. void intercambiar (float& valor1, float& valor2)
  127. {
  128.   float temp = valor1;
  129.   valor1 = valor2, valor2 = temp;
  130. }
  131.  
  132. void visualizar_datos (float *dat, const int tam)
  133. {
  134.   for (register int i = 0; i < tam; i++)
  135.     cout << dat[i] << ' ';
  136. }
  137. ende
  138. end
  139.  
  140. ; LECCION 3
  141. begin
  142. begine " CLASE ent "
  143. /*
  144.   La función main() prueba la clase ent. La clase ent es similar al tipo int,
  145.   diferenciándose en el tratamiento cuando se intenta sobrepasar los valores
  146.   límites.
  147. */
  148.  
  149. #include <iostream.h>
  150. #include <conio.h>
  151. #include <limits.h>
  152.  
  153. class ent
  154. {
  155.   int valor;
  156.  
  157.   public:
  158.  
  159.   void asig (int v = 0)  { valor = v; }
  160.   void incr (void)       { if (valor < INT_MAX) valor++; }
  161.   void decr (void)       { if (valor > INT_MIN) valor--; }
  162.   int val (void)         { return valor; }
  163. };
  164.  
  165. void main (void)
  166. {
  167.   int i;
  168.   ent e;
  169.  
  170.   cout << "EJEMPLO DE LA CLASE ent\n\n";
  171.  
  172.   cout << "i: " << (i = INT_MAX) << '\n';
  173.   cout << "e: " << (e.asig (INT_MAX), e.val ()) << '\n';
  174.   cout << "++i: " << ++i << '\n';
  175.   cout << "++e: " << (e.incr (), e.val ()) << '\n';
  176.   cout << "i: " << (i = INT_MIN) << '\n';
  177.   cout << "e: " << (e.asig (INT_MIN), e.val ()) << '\n';
  178.   cout << "--i: " << --i << '\n';
  179.   cout << "--e: " << (e.decr (), e.val ()) << '\n';
  180.  
  181.   getch ();
  182. }
  183. ende
  184. begine " CLASE cola_char "
  185. /*
  186.   Este ejemplo consiste en la creación de una clase cola_char y una función
  187.   main() para probar dicha clase. En la cola de caracteres se pueden realizar
  188.   dos operaciones: introducir y sacar caracteres, teniendo en cuenta siempre
  189.   que el primer elemento introducido es el primer elemento a sacar.
  190. */
  191.  
  192. #include <iostream.h>
  193. #include <conio.h>
  194.  
  195. #define MAX 256
  196.  
  197. class cola_char
  198.   {
  199.     char c[MAX];
  200.     int posinic, posfinal;
  201.  
  202.     public:
  203.  
  204.     void inicializar_cola (void)
  205.     {
  206.       posfinal = 1; posinic = 0;
  207.     }
  208.  
  209.     char guardar_en_cola (char car)
  210.     {
  211.       return (posfinal == MAX ? 0 : (c[posfinal++] = car));
  212.     }
  213.  
  214.     char devolver_de_cola (void)
  215.     {
  216.       return (posinic + 1 == posfinal ? 0 : c[++posinic]);
  217.     }
  218.   };
  219.  
  220. void main (void)
  221. {
  222.   char s[MAX];
  223.   cola_char cola;
  224.   char ch;
  225.  
  226.   cout << "EJEMPLO DE LA CLASE cola_char\n\n";
  227.  
  228.   cola.inicializar_cola ();
  229.   cout << "Introduce cadena a introducir en la cola de caracteres: ";
  230.   cin >> s;
  231.   for (char *ps = s; *ps && cola.guardar_en_cola (*ps); ps++)
  232.     ;
  233.   cout << "Cadena sacada de la cola: ";
  234.   while ((ch = cola.devolver_de_cola ()) != 0)
  235.     cout << ch;
  236.  
  237.   getch ();
  238. }
  239. ende
  240. end
  241.  
  242. ; LECCION 4
  243. begin
  244. begine " CLASE conj_int "
  245. /*
  246.   Este programa implementa la clase conj_int (conjunto de enteros) y
  247.   desarrolla una función main() para testear dicha clase. La función
  248.   main() crea e imprime un conjunto de números enteros aleatorios.
  249. */
  250.  
  251. #include <iostream.h>
  252. #include <conio.h>
  253. #include <stdlib.h>
  254. #include <time.h>
  255.  
  256. class conj_int
  257.   {
  258.     int tamact, tammax;
  259.     int *x;
  260.  
  261.     public:
  262.  
  263.     conj_int (int m, int n);  // como mucho m enteros en el rango 1...n
  264.     ~conj_int (void);
  265.  
  266.     int miembro (int elem);   // ¿es "elem" un miembro?
  267.     void insertar (int elem); // añade "elem" al conjunto
  268.  
  269.     // estas tres funciones son proporcionadas para que el usuario puede acceder
  270.     // a los elementos del conjunto en algún orden
  271.     void iterar (int& i)      { i = 0; }             // inicializa una iteración
  272.     int ok (int& i)           { return i < tamact; } // chequea si hay un miembro siguiente
  273.     int siguiente (int& i)    { return x[i++]; }     // obtiene el siguiente miembro
  274.   };
  275.  
  276. inline void inicializar_generador_de_numeros_aleatorios (void)
  277. {
  278.   srand (unsigned (time (NULL)));
  279. }
  280.  
  281. inline int randint (int tope) // en el rango 1..tope
  282. {
  283.   return 1 + rand() % tope;
  284. }
  285.  
  286. void main (void)
  287. {
  288.   void imprimir_en_orden (conj_int&);
  289.  
  290.   cout << "EJEMPLO DE LA CLASE conj_int\n\n";
  291.  
  292.   int contador = 0;
  293.   int m, n;
  294.  
  295.   cout << "Introduce el número de miembros del conjunto: ";
  296.   cin >> m;
  297.  
  298.   cout << "Introduce el valor máximo de los miembros del conjunto: ";
  299.   cin >> n;
  300.  
  301.   conj_int conj (m, n);
  302.  
  303.   inicializar_generador_de_numeros_aleatorios ();
  304.   while (contador < m)
  305.     {
  306.       int t = randint (n);
  307.       if (conj.miembro (t) == 0) // evita elementos duplicados en el conjunto
  308.         {
  309.           conj.insertar (t);
  310.           contador++;
  311.         }
  312.     }
  313.  
  314.   cout << "Elementos en el conjunto de enteros: ";
  315.   imprimir_en_orden (conj);
  316.  
  317.   getch ();
  318. }
  319.  
  320. void error (char *s)
  321. {
  322.   cerr << "\n" << "conjunto: " << s << "\n";
  323.   getch ();
  324.   exit (1);
  325. }
  326.  
  327. conj_int::conj_int (int m, int n) // como mucho m enteros en el rango 1..n
  328. {
  329.   if (m < 1 || n < m)
  330.     error ("tamaño de conj_int ilegal");
  331.   tamact = 0;
  332.   tammax = m;
  333.   x = new int[tammax];
  334. }
  335.  
  336. conj_int::~conj_int (void)
  337. {
  338.   delete x;
  339. }
  340.  
  341. void conj_int::insertar (int elem)
  342. {
  343.   if (++tamact > tammax)
  344.     error ("demasiados elementos");
  345.   int i;
  346.  
  347.   for (i = tamact - 1, x[i] = elem; i > 0 && x[i-1] > x[i]; i--)
  348.     {
  349.       int elem = x[i]; // intercambia x[i] y x[i-1]
  350.       x[i] = x[i-1];
  351.       x[i-1] = elem;
  352.     }
  353. }
  354.  
  355. int conj_int::miembro (int elem) // búsqueda binaria
  356. {
  357.   int ibaj = 0, ialt = tamact - 1;
  358.  
  359.   while (ibaj <= ialt)
  360.     {
  361.       int imed = (ibaj + ialt) / 2;
  362.       if (elem < x[imed])
  363.         ialt = imed - 1;
  364.       else if (elem > x[imed])
  365.         ibaj = imed + 1;
  366.       else
  367.         return 1; // encontrado
  368.     }
  369.   return 0;      // no encontrado
  370. }
  371.  
  372. void imprimir_en_orden (conj_int& conjunto)
  373. {
  374.   int var;
  375.   conjunto.iterar (var);
  376.   while (conjunto.ok (var))
  377.     cout << conjunto.siguiente (var) << " ";
  378. }
  379. ende
  380. begine " CLASE lista "
  381. /*
  382.   Este programa implementa la clase lista, la cual maneja una lista lineal
  383.   enlazada de caracteres. La función main() es un test para probar la clase
  384.   lista.
  385. */
  386.  
  387. #include <iostream.h>
  388.  
  389. #ifndef NULL      // en algunos sistemas puede que no esté definido en
  390. #  define NULL 0  // iostream.h o stream.h
  391. #endif
  392.  
  393. struct nodo_lista
  394.   {
  395.     char dato;
  396.     nodo_lista *psiguiente;
  397.   };
  398.  
  399. class lista
  400.   {
  401.     nodo_lista *pcabeza; // cabeza de la lista
  402.  
  403.     public:
  404.  
  405.     lista (void) { pcabeza = NULL; }
  406.     ~lista (void) { liberar (); }
  407.  
  408.     void aniadir (char c) // inserta al principio de la lista
  409.     {
  410.       nodo_lista *ptemp = new nodo_lista; // crea un nuevo elemento
  411.       ptemp->psiguiente = pcabeza; // enlaza con lista
  412.       ptemp->dato = c;
  413.       pcabeza = ptemp; // actualiza la cabeza de la lista
  414.     }
  415.  
  416.     void quitar (void) // quita primer elemento de la lista
  417.     {
  418.       nodo_lista *ptemp = pcabeza;
  419.       pcabeza = pcabeza->psiguiente;
  420.       delete ptemp;
  421.     }
  422.  
  423.     nodo_lista *primero (void) { return pcabeza; }
  424.     void imprimir_lista (void);
  425.     void lista::liberar (void);
  426.   };
  427.  
  428. void lista::imprimir_lista (void)
  429. {
  430.   for (nodo_lista *ptemp = pcabeza; ptemp != NULL; ptemp = ptemp->psiguiente)
  431.     cout << ptemp->dato << " -> ";
  432.   cout << "NULL\n";
  433. }
  434.  
  435. void lista::liberar (void)
  436. {
  437.   while (pcabeza != NULL)
  438.     quitar ();
  439. }
  440.  
  441. void main (void)
  442. {
  443.   char s[256];
  444.   lista list;
  445.  
  446.   cout << "EJEMPLO DE LA CLASE lista\n\n";
  447.  
  448.   cout << "Introduce cadena a introducir en la lista de caracteres: ";
  449.   cin >> s;
  450.   for (char *ps = s; *ps; ps++)
  451.     list.aniadir (*ps);
  452.   cout << "Contenido de la lista: ";
  453.   list.imprimir_lista ();
  454.  
  455.   getch ();
  456. }
  457. ende
  458. begine " CLASE timer "
  459. /*
  460.   Este ejemplo implementa la clase timer (contador de tiempo) junto con la
  461.   función main() para probarla.
  462.  
  463.   La clase timer es más útil de lo que puede parecer a simple vista, ya que
  464.   permite realizar programas que funcionan a la misma velocidad en cualquier
  465.   tipo de ordenador. Esto es especialmente importante en los juegos de orde-
  466.   nadores.
  467.  
  468.   Si tienes un ordenador que funciona en modo turbo y en modo normal, puedes
  469.   cambiar entre modos turbo y normal mientras se ejecuta este programa para
  470.   comprobar que las dos frases siguen escribiéndose a la misma velocidad.
  471.  
  472.   Como en todos los programas ejemplos del tutor de C++, es conveniente
  473.   declarar la clase, las funciones inline y las declaraciones (no defini-
  474.   ciones) de las variables globales y funciones no inline en un fichero de
  475.   cabecera, y las definiciones de las funciones no inline y de las variables
  476.   globales en fichero con extensión CPP. Por ejemplo, tendríamos entonces
  477.   los ficheros timer.h y timer.cpp; en el fichero timer.cpp debemos incluir
  478.   timer.h y entonces compilarlo para obtener el fichero objeto: timer.obj.
  479.   Una vez que hemos hecho todo esto, para utilizar esta clase en un programa,
  480.   debemos incluir, bien el fichero timer.cpp o bien el fichero timer.obj, en
  481.   el fichero de proyecto; además, en el fichero que se encuentra nuestro
  482.   programa incluimos el fichero de cabecera timer.h. Compilando el fichero
  483.   de proyecto, tenemos el programa ejecutable final. Si nuestro programa no
  484.   se va a desarrollar como proyecto, simplemente incluiremos el fichero
  485.   timer.cpp en el fichero que forma nuestro programa. Este proceso, insisto,
  486.   es válido para todos los programas ejemplos del tutor de C++.
  487. */
  488.  
  489. #include <iostream.h> // cout
  490. #include <time.h>     // clock (), CLK_TCK, clock_t
  491. #include <conio.h>    // getch ()
  492.  
  493. // La clase timer permite ejecutar retrasos y sincronizaciones, sin
  494. // necesidad de inicializaciones o variables adicionales.
  495.  
  496. class timer
  497.   {
  498.     private:
  499.       clock_t tinicial;
  500.     public:
  501.       timer (void);
  502.       void esperar (int pulsos);
  503.       void esperar (double segundos);
  504.       void sincronizar (int pulsos);
  505.       void sincronizar (double segundos);
  506.   };
  507.  
  508. // Cada vez que se crea un objeto (ya sea por declaración o utilizando new),
  509. // su constructor almacena en tinicial el instante de creación.
  510.  
  511. inline timer::timer (void)
  512. {
  513.   tinicial = clock ();
  514. }
  515.  
  516. /*
  517.   El argumento correcto para las dos funciones esperar debería ser unsigned.
  518.   Para ello hay dos soluciones, bien llamar a cada función esperar con un
  519.   nombre distinto, o bien llamar a las dos funciones iguales (sobrecarga de
  520.   funciones) y hacer que los argumentos sean distintos. En este caso, y por
  521.   cuestiones de claridad, es mejor optar por la segunda solución. Ejemplo:
  522.     esperar (10);   // espera 10 pulsos de reloj
  523.     esperar (10.0); // espera 10 segundos
  524.   El motivo de elegir int y double en vez de otra combinación (por ejemplo,
  525.   unsigned y double, o int y long) es por motivo de errores de ambigüedad
  526.   en las conversiones implícitas.
  527.   Con las dos funciones de sincronizar ocurre lo mismo.
  528. */
  529.  
  530. // espera el número indicado de pulsos
  531.  
  532. void timer::esperar (int pulsos)
  533. {
  534.   clock_t tfinal = clock () + pulsos;
  535.   while (clock () < tfinal)
  536.     ;
  537. }
  538.  
  539. // espera el número indicado de segundos
  540.  
  541. inline void timer::esperar (double segundos)
  542. {
  543.   esperar (int (segundos * CLK_TCK) + 1);
  544. }
  545.  
  546. // sincroniza el número indicado de pulsos
  547.  
  548. void timer::sincronizar (int pulsos)
  549. {
  550.   clock_t tfinal = tinicial + pulsos;
  551.   while (clock () < tfinal)
  552.     ;
  553.   tinicial = clock ();
  554. }
  555.  
  556. // sincroniza el número indicado de segundos
  557.  
  558. inline void timer::sincronizar (double segundos)
  559. {
  560.   sincronizar (int (segundos * CLK_TCK) + 1);
  561. }
  562.  
  563. void main (void)
  564. {
  565.   timer t;
  566.   register const char *p;
  567.   const char *frase1 = "Esta es la primera frase.";
  568.   const char *frase2 = "Esta es la segunda frase.";
  569.  
  570.   clrscr ();
  571.  
  572.   cout << "\nEjemplo de la clase timer. En la primera frase, cada letra se "
  573.           "escribirá un\ncuarto de segundo después de que se haya terminado "
  574.           "de escribir la anterior.\nEn la segunda frase, cada letra se "
  575.           "escribirá un cuarto de segundo después\n de que se haya empezado "
  576.           "a escribir la anterior.\n\n";
  577.  
  578.   for (t.sincronizar (0.0), p = frase1; *p; p++)
  579.     {
  580.       cout << *p;
  581.       t.esperar (int (CLK_TCK / 4));
  582.     }
  583.  
  584.   for (cout << '\n', t.sincronizar (0.0), p = frase2; *p; p++)
  585.     {
  586.       cout << *p;
  587.       t.sincronizar (int (CLK_TCK / 4));
  588.     }
  589.  
  590.   cout << "\n\nPulsa cualquier tecla para salir de programa.";
  591.   getch ();
  592. }
  593. ende
  594. begint
  595. begine " CLASE video "
  596. /*
  597.   Este ejemplo implementa la clase video y una función main para probar dicha
  598.   clase.
  599.  
  600.   La clase vídeo ofrece una implementación para poder acceder directamente a
  601.   la memoria RAM de vídeo.
  602.  
  603.   El acceso directo a la memoria RAM de vídeo es mucho más rápido que el acceso
  604.   vía interrupciones de la ROM BIOS. La desventaja que tiene con respecto al
  605.   uso de dichas interrupciones es que es menos portable; no obstante, en la
  606.   inmensa mayoría de los sistemas coincide la dirección de comienzo de la me-
  607.   moria de vídeo: 0xB000:0x0000 para tarjetas monocromas (no monitores mono-
  608.   cromos) y 0xB800:0x0000 para tarjetas color.
  609.  
  610.   Es importante hacer notar que la clase vídeo está implementada para que
  611.   funcione sólamente con el modo de vídeo 80x25, es decir, el modo de vídeo
  612.   que trabaja con 80 columnas y 15 filas. Para utilizar otros modos de vídeo
  613.   sólo hace falta modificar las macros DIMX (dimensión del eje x) y DIMY (di-
  614.   mensión del eje y). Sin embargo, sería más interesante que la propia clase
  615.   averiguara cúal es el modo de pantalla actual; esto se deja como ejercicio.
  616. */
  617.  
  618. #include <dos.h>      // MK_FP ()
  619. #include <graphics.h> // detectgraph (), HERCMONO
  620. #include <conio.h>    // getch ()
  621.  
  622. #define DIMX 80
  623. #define DIMY 25
  624.  
  625. // esta clase permite escribir (leer) carácteres en (de) la consola utilizando
  626. // directamente la memoria RAM de vídeo, es decir, el acceso a la memoria de
  627. // de vídeo no se hace vía interrupción de la ROM BIOS que sería más lento,
  628. // aunque también más portable
  629. class video
  630.   {
  631.     private :
  632.  
  633.       unsigned int (far *pantalla) [DIMX];
  634.       unsigned char atributo;
  635.  
  636.     public :
  637.  
  638.       // constructor: inicializa las dos variables privadas
  639.       // - pantalla apunta al principio de la memoria de vídeo
  640.       // - atributo se pone por defecto en blanco sobre negro (0x07)
  641.       video (void)
  642.       {
  643.         int gd, gm;
  644.         detectgraph (&gd, &gm);
  645.         pantalla = (unsigned int (far *) [DIMX])
  646.                    MK_FP (gd == HERCMONO ? 0xB000 : 0xB800, 0);
  647.         atributo = 7; // blanco sobre negro
  648.       }
  649.  
  650.       // escribe el carácter caract con el atributo atr en la posición (x,y)
  651.       // de la pantalla sin comprobar que dicha posición está dentro de la
  652.       // pantalla
  653.       void _escr (int x, int y, int caract, unsigned char atr)
  654.       {
  655.         // (unsigned char) para escribir bien los códigos ascii > 128
  656.         // pantalla[y-1][x-1] == (*(pantalla+y-1))[x-1] == *(*(pantalla+y-1)+x-1)
  657.         *(*(pantalla+y-1)+x-1) = (atr << 8) + (unsigned char) caract;
  658.       }
  659.  
  660.       // escribe el carácter caract con el atributo actual de pantalla en la
  661.       // posición (x,y) de la pantalla sin comprobar que dicha posición está
  662.       // dentro de la pantalla
  663.       void _escr (int x, int y, int caract)
  664.       {
  665.         _escr (x, y, caract, atributo);
  666.       }
  667.  
  668.       // escribe el carácter caract con el atributo atr de pantalla en la
  669.       // posición (x,y) de la pantalla si esta posición es correcta
  670.       void escr (int x, int y, int caract, unsigned atr)
  671.       {
  672.         if (x >= 1 && x <= DIMX && y >= 1 && y <= DIMY)
  673.           _escr (x, y, caract, atr);
  674.       }
  675.  
  676.       // escribe el carácter caract con el atributo actual de pantalla en la
  677.       // posición (x,y) de la pantalla si esta posición es correcta
  678.       void escr (int x, int y, int caract)
  679.       {
  680.         escr (x, y, caract, atributo);
  681.       }
  682.  
  683.       // devuelve carácter que hay en la posicón (x,y) de la pantalla
  684.       char leerc (int x, int y)
  685.       {
  686.         return pantalla[y-1][x-1];
  687.       }
  688.  
  689.       // devuelve el atributo de pantalla de la posición (x,y) de ésta
  690.       char leera (int x, int y)
  691.       {
  692.         return (pantalla[y-1][x-1] >> 4);
  693.       }
  694.  
  695.       // devuelve el carácter que hay en la posición (x,y) de la pantalla
  696.       int leer (int x, int y)
  697.       {
  698.         return pantalla[y-1][x-1];
  699.       }
  700.  
  701.       // pone el atributo actual de pantalla
  702.       void poner_atributo (unsigned char atr)
  703.       {
  704.         atributo = atr;
  705.       }
  706.   };
  707.  
  708. void main (void)
  709. {
  710.   video vid;
  711.  
  712.   for (register int x = 1; x <= DIMX; x++)
  713.     for (register int y = 1; y <= DIMY; y++)
  714.       vid._escr (x, y, x <= DIMX / 2 ? '▒' : '▓', y <= DIMY / 2 ? 0x07 : 0x70);
  715.   for (x = 1; x <= DIMX; x++)
  716.     vid._escr (x, DIMY, '░', x <= DIMX / 2 ? 0x07 : 0x70);
  717.  
  718.   vid.escr (DIMX + 1, DIMY + 1, '*'); // el carácter '*' no se escribirá
  719.  
  720.   getch ();
  721. }
  722. ende
  723. endt
  724. end
  725.  
  726. ; LECCION 5
  727. begin
  728. begine " CLASE pot "
  729. /*
  730.   Este ejemplo implementa la clase pot. La función main() prueba dicha clase.
  731.   La clase pot nos permite elevar un número a la potencia de otro utilizando
  732.   el operador ^ que es mucho más cómodo que utilizar la función pow().
  733.  
  734.   Notad que dependiendo de los operandos del operador ^, el compilador lo
  735.   interpreta como operador XOR u operador de potencia.
  736. */
  737.  
  738. #include <iostream.h> // cout, << sobrecargado
  739. #include <conio.h>    // getch ()
  740. #include <math.h>     // pow ()
  741.  
  742. class pot
  743.   {
  744.     private:
  745.       double num;
  746.  
  747.     public:
  748.       pot (double d = 0.0) { num = d; }
  749.       friend double operator^ (pot num1, pot num2) { return pow (num1, num2); }
  750.       operator double () { return num; }
  751.   };
  752.  
  753. inline void imprimir_operacion (const char *operacion)
  754. {
  755.   cout << "\n*** Ejecutando: " << operacion;
  756. }
  757.  
  758. inline void imprimir_variables (pot x, pot y, double z)
  759. {
  760.   cout << "\nx = " << double (x) << "\ny = " << double (y) << "\nz = " << z;
  761. }
  762.  
  763. void main (void)
  764. {
  765.   cout << "EJEMPLO DE LA CLASE pot\n\n";
  766.  
  767.   cout << "\n*** Declarando: pot x = 5.5, y; double z = x;";
  768.   pot x = 5.5, y; double z = x;
  769.   imprimir_variables (x, y, z);
  770.  
  771.   imprimir_operacion ("y = z = x;");
  772.   y = z = x;
  773.   imprimir_variables (x, y, z);
  774.  
  775.   imprimir_operacion ("x = -2 + double (5) - pot (1);");
  776.   x = -2 + double (5) - pot (1);
  777.   imprimir_variables (x, y, z);
  778.  
  779.   imprimir_operacion ("y = z ^ x;");
  780.   y = z ^ x;
  781.   imprimir_variables (x, y, z);
  782.  
  783.   imprimir_operacion ("z += x ^ (3 ^ 2);");
  784.   z += x ^ (3 ^ 2); // 3 ^ 2 == 1 => XOR.  x ^ 1 == x => POT
  785.   imprimir_variables (x, y, z);
  786.  
  787.   getch ();
  788. }
  789. ende
  790. begine " CLASE vect "
  791. /*
  792.   En este ejemplo se implementa la clase vect. La función main() prueba esta
  793.   clase.
  794.  
  795.   La clase vect implementa un vector de enteros en el se chequea el rango
  796.   cada vez que se accede al vector para asegurar que no accedamos a un
  797.   elemento inexistente. Además, sobrecarga algunos operadores para realizar
  798.   determinadas operaciones aritméticas y de asignación con los elementos de
  799.   los vectores.
  800.  
  801.   Notad que las funciones de los operadores de asignación y la de indexado
  802.   devuelven una referencia a vect mientras que las funciones de los operadores
  803.   aritméticos devuelven un vect (esto es, un objeto temporal). Esto se suele
  804.   hacer así en estos casos para permitir las siguientes sentencias:
  805.     x[1] = 10;
  806.     x = y = z;
  807.   y para prohibir las siguientes:
  808.     x + y = z;
  809.     -x = y;
  810. */
  811.  
  812. #include <iostream.h> // cout, cin
  813. #include <stdlib.h>   // exit()
  814. #include <conio.h>    // getch()
  815.  
  816. // Un tipo seguro de array: chequea rangos
  817. class vect
  818.   {
  819.     int *p;                             // puntero base
  820.     int tam;                            // número de elementos
  821.  
  822.     public:
  823.  
  824.     // constructores y destructor
  825.     vect (void);                        // crea un array de 10 elementos
  826.     vect (int n);                       // crea un array de n elementos
  827.     vect (vect& v);                     // inicialización por vector
  828.     vect (int a[], int n);              // inicialización por array
  829.     ~vect (void) { delete p; }
  830.  
  831.     // otras funciones miembros
  832.     int is (void) { return (tam - 1); } // índice superior
  833.     int& operator [] (int i);
  834.     vect& operator = (vect& v);
  835.     vect& operator += (vect& v);
  836.     vect& operator -= (vect& v);
  837.     vect operator - (void);
  838.     vect operator + (void) { return (*this); }
  839.     vect operator - (vect& v);
  840.     vect operator + (vect& v);
  841.  
  842.     void imprimir (const char *mensaje);
  843.   };
  844.  
  845. void error (const char *msj)
  846. {
  847.   cerr << "\nError en clase vect: " << msj << "\n";
  848.   getch ();
  849.   exit (1);
  850. }
  851.  
  852. vect::vect (void)
  853. {
  854.   p = new int[tam = 10];
  855. }
  856.  
  857. vect::vect (int n)
  858. {
  859.   if (n < 0)
  860.     error ("Tamaño ilegal de vector.");
  861.   p = new int[tam = n];
  862. }
  863.  
  864. vect::vect (int a[], int n)
  865. {
  866.   if (n < 0)
  867.     error ("Tamaño ilegal de vector.");
  868.   p = new int[tam = n];
  869.   for (int i = 0; i < tam; ++i)
  870.     p[i] = a[i];
  871. }
  872.  
  873. vect::vect (vect& v)
  874. {
  875.   p = new int[tam = v.tam];
  876.   for (int i = 0; i < tam; ++i)
  877.     p[i] = v.p[i];
  878. }
  879.  
  880. int& vect::operator [] (int i)
  881. {
  882.   if (i < 0 || i > is ())
  883.     error ("Indice de vector ilegal.");
  884.   return p[i];
  885. }
  886.  
  887. vect& vect::operator = (vect& v)
  888. {
  889.   int t = tam < v.tam ? tam : v.tam;
  890.   if (v.tam != tam)
  891.     error ("Intento de copiar arrays de tamaños diferentes.");
  892.   for (int i = 0; i < t; ++i)
  893.     p[i] = v.p[i];
  894.   return *this;
  895. }
  896.  
  897. vect& vect::operator += (vect& v)
  898. {
  899.   return (*this = *this + v);
  900. }
  901.  
  902. vect& vect::operator -= (vect& v)
  903. {
  904.   return (*this = *this - v);
  905. }
  906.  
  907. vect vect::operator - (void)
  908. {
  909.   vect neg (*this);
  910.   for (int i = 0; i < tam; ++i)
  911.     neg.p[i] = -neg.p[i];
  912.   return neg;
  913. }
  914.  
  915. vect vect::operator - (vect& v)
  916. {
  917.   int t = tam < v.tam ? tam : v.tam;
  918.   vect dif (t);
  919.   if (v.tam != tam)
  920.     error ("Intento de sumar arrays de tamaños diferentes.");
  921.   for (int i = 0; i < t; ++i)
  922.     dif.p[i] = p[i] - v.p[i];
  923.   return dif;
  924. }
  925.  
  926. vect vect::operator + (vect& v)
  927. {
  928.   return (*this - -v);
  929. }
  930.  
  931. void vect::imprimir (const char *mensaje)
  932. {
  933.   cout << '\n' << mensaje << ": [";
  934.   for (register int i = 0; i < tam; i++)
  935.     cout << ' ' << p[i];
  936.   cout << " ]";
  937. }
  938.  
  939. void imprimir_operacion (const char *operacion,
  940.                          vect& vectx, vect& vecty, vect& vectz)
  941. {
  942.   cout << "\nEjecutando: " << operacion;
  943.   vectx.imprimir ("Vector x");
  944.   vecty.imprimir ("Vector y");
  945.   vectz.imprimir ("Vector z");
  946.   cout << '\n';
  947.   getch ();
  948. }
  949.  
  950. void main (void)
  951. {
  952.   cout << "EJEMPLO DE LA CLASE vect\n\n";
  953.  
  954.   int n;
  955.   register int i;
  956.  
  957.   do
  958.     {
  959.       cout << "Introduce número de elementos de los vectores x e y: ";
  960.       cin >> n;
  961.     } while (n <= 0);
  962.  
  963.   int *vx = new int[n], *vy = new int[n];
  964.  
  965.   cout << "Introduce los " << n << " elementos del vector x: ";
  966.   for (i = 0; i < n; i++)
  967.    cin >> vx[i];
  968.  
  969.   cout << "Introduce los " << n << " elementos del vector y: ";
  970.   for (i = 0; i < n; i++)
  971.    cin >> vy[i];
  972.  
  973.   vect x (vx, n), y (vy, n), z (n);
  974.   imprimir_operacion ("inicialización de los vectores x, y", x, y, z);
  975.  
  976.   z = x + y;
  977.   imprimir_operacion ("z = x + y;", x, y, z);
  978.  
  979.   x += y = -z;
  980.   imprimir_operacion ("x += y = -z;", x, y, z);
  981.  
  982.   y = z - (x = y);
  983.   imprimir_operacion ("y = z - (x = y);", x, y, z);
  984.  
  985.   y += z -= x;
  986.   imprimir_operacion ("y += z -= x;", x, y, z);
  987.  
  988.   z = -(- (x - (+y) - z));
  989.   imprimir_operacion ("z = -(- (x - (+y) - z));", x, y, z);
  990.  
  991.   y = -(-z - -x);
  992.   imprimir_operacion ("y = -(-z - -x);", x, y, z);
  993.  
  994.   cout << "\nEjecutando: x[" << n << "];";
  995.   x[n];
  996.  
  997.   delete vx;
  998.   delete vy;
  999. }
  1000. ende
  1001. begine " CLASE intpeq "
  1002. /*
  1003.   Este ejemplo implementa la clase intpeq junto con la función main() para
  1004.   probar esta clase.
  1005.  
  1006.   La clase intpeq es igual que la clase int con la excepción de que los
  1007.   objetos del tipo intpeq sólo pueden tomar valores entre 0 y 63. El rango
  1008.   sólo se chequea cuando un intpeq es inicializado con un int y cuando se
  1009.   asigna un int a un intpeq.
  1010. */
  1011.  
  1012. #include <iostream.h>
  1013. #include <conio.h>
  1014.  
  1015. inline void err (const char *mensaje_de_error)
  1016. {
  1017.   cout << '\n' << mensaje_de_error;
  1018. }
  1019.  
  1020. class intpeq
  1021. {
  1022.   char val;
  1023.   int asign (int i) { return val = (i&~63) ? (err ("error de rango"), 0) : i; }
  1024.  
  1025.   public:
  1026.  
  1027.   intpeq (int i)             { asign (i); }
  1028.   intpeq (intpeq& ip)        { val = ip.val; } // no chequeo de rango (innecesario)
  1029.   int operator= (int i)      { return asign (i); }
  1030.   int operator= (intpeq& ip) { return val = ip.val; } // no chequeo de rango
  1031.   operator int ()            { return val; }
  1032. };
  1033.  
  1034. inline void impr_operacion (const char *operacion)
  1035. {
  1036.   cout << "\n*** Ejecutando: " << operacion;
  1037. }
  1038.  
  1039. inline void impr_variables (intpeq x, intpeq y, int z)
  1040. {
  1041.   cout << "\nx = " << int (x) << "\ny = " << int (y) << "\nz = " << z;
  1042. }
  1043.  
  1044. void main (void)
  1045. {
  1046.   cout << "EJEMPLO DE LA CLASE intpeq";
  1047.  
  1048.   cout << "\n*** Declarando: intpeq x = 3, y = 62; int z = 64;";
  1049.   intpeq x = 3, y = 62; int z = 64;
  1050.   impr_variables (x, y, z);
  1051.  
  1052.   impr_operacion ("y = x + y, x = z;");
  1053.   y = x + y, x = z;
  1054.   impr_variables (x, y, z);
  1055.  
  1056.   impr_operacion ("x = y * 2 + z - 4;");
  1057.   x = y * 2 + z - 4;
  1058.   impr_variables (x, y, z);
  1059.  
  1060.   impr_operacion ("y = x * x;");
  1061.   y = x * x;
  1062.   impr_variables (x, y, z);
  1063.  
  1064.   impr_operacion ("z = x + 10, x = -1;");
  1065.   z = x + 10, x = -1;
  1066.   impr_variables (x, y, z);
  1067.  
  1068.   getch ();
  1069. }
  1070. ende
  1071. begine " CLASE arbol_binario "
  1072. /*
  1073.   Este programa implementa la clase arbol_binario junto con una función main()
  1074.   para probarla.
  1075.  
  1076.   La clase arbol_binario permite al usuario realizar varias operaciones con
  1077.   árboles binarios: insertar, buscar, quitar, listar, ...
  1078. */
  1079.  
  1080. #include <iostream.h> // cout, cin, cerr
  1081. #include <stdlib.h>   // exit (), NULL
  1082. #include <conio.h>    // getch ()
  1083.  
  1084. enum boolean { false, true };
  1085.  
  1086. struct nodo_arbol_binario
  1087.   {
  1088.     friend class arbol_binario;
  1089.  
  1090.     private:
  1091.  
  1092.     char dato;
  1093.     nodo_arbol_binario *pizquierdo, *pderecho;
  1094.  
  1095.   };
  1096.  
  1097. class arbol_binario
  1098.   {
  1099.     nodo_arbol_binario *parbol; // puntero a la cabeza del árbol
  1100.  
  1101.     public:
  1102.  
  1103.     arbol_binario (void) { parbol = NULL; }
  1104.     ~arbol_binario (void) { liberar_arbol (); }
  1105.  
  1106.     void liberar_arbol (void) { liberar (parbol); parbol = NULL; }
  1107.     void insertar (char dat);
  1108.     boolean quitar_de_arbol (char dat);
  1109.     boolean buscar_en_arbol (char dat) { return boolean (buscar (dat) != NULL); }
  1110.  
  1111.     void imprimir_arbol_en_preorden (void) { imprimir_en_preorden (parbol); }
  1112.     void imprimir_arbol_en_postorden (void) { imprimir_en_postorden (parbol); }
  1113.     void imprimir_arbol_en_inorden (void) { imprimir_en_inorden (parbol); }
  1114.  
  1115.     private:
  1116.  
  1117.     nodo_arbol_binario *buscar (char dat);
  1118.     void suprimir_nodo_de_arbol (nodo_arbol_binario * &p);
  1119.  
  1120.     void imprimir_en_preorden (nodo_arbol_binario *parb);
  1121.     void imprimir_en_postorden (nodo_arbol_binario *parb);
  1122.     void imprimir_en_inorden (nodo_arbol_binario *parb);
  1123.  
  1124.     void liberar (nodo_arbol_binario * &parb);
  1125.  
  1126.     void crear_nodo_arbol (nodo_arbol_binario * &pa)
  1127.     {
  1128.       if ((pa = new nodo_arbol_binario) == NULL)
  1129.         {
  1130.           cerr << "\nERROR: Memoria insuficiente.";
  1131.           getch ();
  1132.           exit (1);
  1133.         }
  1134.     }
  1135.  
  1136.     void liberar_nodo_arbol (nodo_arbol_binario * &pa) { delete pa; }
  1137.   };
  1138.  
  1139. /*
  1140.   Cuando se destruye el objeto árbol es conveniente liberar la memoria
  1141.   asignada dinámicamente. Para ello, lo único que se hace es recorrer
  1142.   todo el árbol liberando cada nodo con delete.
  1143. */
  1144.  
  1145. void arbol_binario::liberar (nodo_arbol_binario * &parb)
  1146. {
  1147.   if (parb != NULL)
  1148.     {
  1149.       liberar (parb->pizquierdo);
  1150.       liberar (parb->pderecho);
  1151.       liberar_nodo_arbol (parb);
  1152.     }
  1153. }
  1154.  
  1155. /*
  1156.   Para ver cómo se inserta en lo árboles, veamos cómo se insertarían
  1157.   los siguientes números en un árbol donde información es un número
  1158.   entero:
  1159.  
  1160.     3 10 2 -1 0 3 8 20
  1161.  
  1162.   Paso 0:
  1163.               parbol
  1164.                 │
  1165.                 v
  1166.                NULL
  1167.   Paso 1:
  1168.               parbol
  1169.                 │
  1170.                 v
  1171.                 3
  1172.   Paso 2:
  1173.               parbol
  1174.                 │
  1175.                 v
  1176.                 3
  1177.                  \
  1178.                   10
  1179.   Paso 3:
  1180.               parbol
  1181.                 │
  1182.                 v
  1183.                 3
  1184.                / \
  1185.               2   10
  1186.   Paso 4:
  1187.               parbol
  1188.                 │
  1189.                 v
  1190.                 3
  1191.                / \
  1192.               2   10
  1193.              /
  1194.            -1
  1195.   Paso 5:
  1196.               parbol
  1197.                 │
  1198.                 v
  1199.                 3
  1200.                / \
  1201.               2   10
  1202.              /
  1203.            -1
  1204.              \
  1205.               0
  1206.   Paso 6:
  1207.               parbol
  1208.                 │
  1209.                 v
  1210.                 3
  1211.                / \
  1212.               2   10
  1213.              /   /
  1214.            -1   3
  1215.              \
  1216.               0
  1217.   Paso 7:
  1218.               parbol
  1219.                 │
  1220.                 v
  1221.                 3
  1222.                / \
  1223.               2   10
  1224.              /   /
  1225.            -1   3
  1226.              \   \
  1227.               0   8
  1228.   Paso 8:
  1229.               parbol
  1230.                 │
  1231.                 v
  1232.                 3
  1233.                / \
  1234.               2   10
  1235.              /   /  \
  1236.            -1   3    20
  1237.              \   \
  1238.               0   8
  1239.  
  1240. */
  1241.  
  1242. void arbol_binario::insertar (char dat)
  1243. {
  1244.   nodo_arbol_binario *p, *pant; /* punteros utilizados para la búsqueda */
  1245.   nodo_arbol_binario *pa; /* puntero que apunta a nuevo nodo creado y que hay que insertar */
  1246.  
  1247.   crear_nodo_arbol (pa);
  1248.   pa->dato = dat;
  1249.   pa->pizquierdo = pa->pderecho = NULL;
  1250.  
  1251.   p = parbol;
  1252.   pant = NULL;
  1253.   while (p != NULL) /* busca lugar de inserción */
  1254.     {
  1255.       pant = p;
  1256.       if (p->dato > dat)
  1257.         p = p->pizquierdo;
  1258.       else
  1259.         p = p->pderecho;
  1260.     }
  1261.  
  1262.   if (pant == NULL) /* inserta en lugar correspondiente */
  1263.     parbol = pa;
  1264.   else if (pant->dato > dat)
  1265.     pant->pizquierdo = pa;
  1266.   else
  1267.     pant->pderecho = pa;
  1268. }
  1269.  
  1270. /*
  1271.   Quita el primer nodo encontrado que contenga el valor dat en el
  1272.   campo información del nodo.
  1273.   Devuelve true si se borró el elemento o false en caso contrario.
  1274. */
  1275.  
  1276. boolean arbol_binario::quitar_de_arbol (char dat)
  1277. {
  1278.   nodo_arbol_binario *p = parbol, *pant = NULL;
  1279.   boolean encontrado = false;
  1280.  
  1281.   while (p != NULL && ! encontrado) /* busca nodo a borrar */
  1282.     if (p->dato == dat)
  1283.       encontrado = true;
  1284.     else
  1285.       {
  1286.         pant = p;
  1287.         if (p->dato > dat)
  1288.           p = p->pizquierdo;
  1289.         else
  1290.           p = p->pderecho;
  1291.       }
  1292.  
  1293.   if (encontrado) /* llama a la función suprimir con puntero apuntado a nodo a quitar */
  1294.     if (p == parbol)
  1295.       suprimir_nodo_de_arbol (parbol);
  1296.     else if (pant->pizquierdo == p)
  1297.       suprimir_nodo_de_arbol (pant->pizquierdo);
  1298.     else
  1299.       suprimir_nodo_de_arbol (pant->pderecho);
  1300.  
  1301.   return (encontrado);
  1302. }
  1303.  
  1304. /*
  1305.   Suprime nodo de árbol apuntado por p.
  1306.   Esta función es llamada por la función quitar_de_arbol.
  1307.  
  1308.   Hay tres situaciones diferentes a la hora de suprimir un nodo, a saber:
  1309.  
  1310.   Sea el árbol compuesto de números reales:
  1311.  
  1312.                                         5
  1313.                                       /   \
  1314.                                      3     8
  1315.                                     / \   / \
  1316.                                    2   4 6   9
  1317.                                   /     / \
  1318.                                  1    5.5  7
  1319.                                           /
  1320.                                          6.5
  1321.  
  1322.   Situación 1: suprimir nodo sin hijo derecho; por ejemplo, el nodo 7, en
  1323.   este caso el puntero p es el puntero derecho del nodo 6; la acción a
  1324.   realizar es: p = pizq (p).
  1325.  
  1326.   Situación 2: suprimir nodo sin hijo izquierdo; por ejemplo, el nodo 1, en
  1327.   este caso el puntero p es el puntero izquierdo del nodo 2; la acción a
  1328.   realizar es: p = pder (p).
  1329.  
  1330.   Situación 3: suprimir nodo intermedio, es decir, nodo con hijos izquierdo
  1331.   y derecho; por ejemplo, el nodo 8, en este caso el puntero p es el
  1332.   puntero derecho del nodo 5; la acción a realizar es sustituir el contenido
  1333.   del nodo a suprimir (nodo 8) por el mayor contenido entre los nodos del
  1334.   subárbol izquierdo, que se calcula como el nodo más a la derecha a partir
  1335.   del nodo izquierdo del nodo a suprimir, en este caso el nodo izquierdo es
  1336.   6 y recorriendo los punteros a la derecha hasta llegar al final, nos
  1337.   paramos en el nodo 7, copiamos el contenido del nodo 7 en el nodo 8 y
  1338.   ahora tenemos que suprimir un nodo (el 7 en este caso) que ya pertenece
  1339.   a uno de los dos casos anteriores.
  1340. */
  1341.  
  1342. void arbol_binario::suprimir_nodo_de_arbol (nodo_arbol_binario * &p)
  1343. {
  1344.   nodo_arbol_binario *ptemp = p;
  1345.  
  1346.   if (p->pderecho == NULL) /* situación 1 */
  1347.     p = p->pizquierdo;
  1348.   else if (p->pizquierdo == NULL) /* situación 2 */
  1349.     p = p->pderecho;
  1350.   else /* situación 3 */
  1351.     {
  1352.       nodo_arbol_binario *pant = p;
  1353.       ptemp = p->pizquierdo;
  1354.       while (ptemp->pderecho != NULL) /* recorremos punteros a derecha a partir ... */
  1355.         { /* ... puntero a izquierda del nodo apuntado por el puntero a suprimir */
  1356.           pant = ptemp;
  1357.           ptemp = ptemp->pderecho;
  1358.         }
  1359.       p->dato = ptemp->dato;
  1360.       if (pant == p)
  1361.         pant->pizquierdo = ptemp->pizquierdo;
  1362.       else
  1363.         pant->pderecho = ptemp->pizquierdo;
  1364.     }
  1365.  
  1366.   liberar_nodo_arbol (ptemp);
  1367. }
  1368.  
  1369. /*
  1370.   Devuelve un puntero al nodo del árbol que contiene dat. Si ningún nodo
  1371.   del árbol contiene el dato dat, devuelve NULL.
  1372. */
  1373.  
  1374. nodo_arbol_binario *arbol_binario::buscar (char dat)
  1375. {
  1376.   nodo_arbol_binario *p = parbol;
  1377.   boolean encontrado = false;
  1378.  
  1379.   while (p != NULL && ! encontrado)
  1380.     if (p->dato == dat)
  1381.       encontrado = true;
  1382.     else if (p->dato > dat)
  1383.       p = p->pizquierdo;
  1384.     else
  1385.       p = p->pderecho;
  1386.  
  1387.   return (p); /* p valdrá NULL si dat no se ha encontrado */
  1388. }
  1389.  
  1390. // Imprime todos los elementos del árbol parb haciendo un recorrido en preorden.
  1391.  
  1392. void arbol_binario::imprimir_en_preorden (nodo_arbol_binario *parb)
  1393. {
  1394.   if (parb != NULL)
  1395.     {
  1396.       cout << parb->dato;
  1397.       imprimir_en_preorden (parb->pizquierdo); /* imprime subárbol izquierdo */
  1398.       imprimir_en_preorden (parb->pderecho); /* imprime subárbol derecho */
  1399.     }
  1400. }
  1401.  
  1402. // Imprime todos los elementos del árbol parb haciendo un recorrido en postorden.
  1403.  
  1404. void arbol_binario::imprimir_en_postorden (nodo_arbol_binario *parb)
  1405. {
  1406.   if (parb != NULL)
  1407.     {
  1408.       imprimir_en_postorden (parb->pizquierdo); /* imprime subárbol izquierdo */
  1409.       imprimir_en_postorden (parb->pderecho); /* imprime subárbol derecho */
  1410.       cout << parb->dato;
  1411.     }
  1412. }
  1413.  
  1414. //  Imprime todos los elementos del árbol parb haciendo un recorrido en inorden.
  1415. //  Si el árbol está ordenado, este recorrido imprime los elmentos ordenados.
  1416.  
  1417. void arbol_binario::imprimir_en_inorden (nodo_arbol_binario *parb)
  1418. {
  1419.   if (parb != NULL)
  1420.     {
  1421.       imprimir_en_inorden (parb->pizquierdo); /* imprime subárbol izquierdo */
  1422.       cout << parb->dato;
  1423.       imprimir_en_inorden (parb->pderecho); /* imprime subárbol derecho */
  1424.     }
  1425. }
  1426.  
  1427. void main (void)
  1428. {
  1429.   cout << "EJEMPLO DE LA CLASE arbol_binario\n\n";
  1430.  
  1431.   char s[256];
  1432.   arbol_binario arbol;
  1433.  
  1434.   cout << "Introduce cadena a introducir en el árbol: ";
  1435.   cin >> s;
  1436.   for (char *ps = s; *ps; ps++)
  1437.     arbol.insertar (*ps);
  1438.  
  1439.   cout << "\nContenido del árbol en preorden: ";
  1440.   arbol.imprimir_arbol_en_preorden ();
  1441.   cout << "\nContenido del árbol en postorden: ";
  1442.   arbol.imprimir_arbol_en_postorden ();
  1443.   cout << "\nContenido del árbol en inorden: ";
  1444.   arbol.imprimir_arbol_en_inorden ();
  1445.  
  1446.   cout << "\n\nBuscando dato '" << *s << "':"
  1447.        << (arbol.buscar_en_arbol (*s) ? " " : " no ") << "encontrado.";
  1448.   cout << "\nQuitando dato '" << *s << "'.";
  1449.   while (arbol.quitar_de_arbol (*s))
  1450.     ;
  1451.   cout << "\nBuscando dato '" << *s << "':"
  1452.        << (arbol.buscar_en_arbol (*s) ? " " : " no ") << "encontrado.";
  1453.  
  1454.   getch ();
  1455. }
  1456. ende
  1457. begine " CLASE asoc "
  1458. /*
  1459.   Este programa cuenta las ocurrencias de cada palabra leída de la entrada
  1460.   estándar. La entrada estándar es por defecto el teclado pero se puede
  1461.   redirigir el programa para que lea de un fichero.
  1462.  
  1463.   Este programa define la clase asoc (vector asociativo) cuyo interface
  1464.   con el exterior está compuesta por tres funciones: el constructor, el
  1465.   operador sobrecargado [] y una función de impresión.
  1466.  
  1467.   La estructura par sólo es utilizada por la clase asoc, por este motivo
  1468.   sus miembros son privados y sólo tiene acceso a ellos los miembros de
  1469.   la clase asoc. Observad que aunque la estructura par está declarada en
  1470.   el interior de la declaración de la clase asoc, en realidad, es como si
  1471.   estuviera declarada fuera; se ha declarado dentro para indicar al lector
  1472.   que dicha estructura solo es utilizada por la clase asoc.
  1473. */
  1474.  
  1475. #include <iostream.h> // cout, cin
  1476. #include <conio.h>    // getch ()
  1477. #include <string.h>   // strcmp (), strlen (), strcpy ()
  1478.  
  1479. class asoc // vector asociativo
  1480.   {
  1481.     struct par // cada elemento del vector asociativo
  1482.       {
  1483.         friend class asoc; // sólo puede acceder la clase asoc a esta estructura
  1484.  
  1485.         private:
  1486.  
  1487.         char *nombre;
  1488.         int valor;
  1489.       };
  1490.  
  1491.     par *vect;
  1492.     int max;   // tamaño del vector
  1493.     int libre; // índice del primer elemento del vector no usado
  1494.  
  1495.     public:
  1496.  
  1497.     asoc (int);
  1498.     int& operator[] (char *);
  1499.     void imprimir_todo (void);
  1500.   };
  1501.  
  1502. asoc::asoc (int tam)
  1503. {
  1504.   max = tam < 16 ? tam : 16;
  1505.   libre = 0;
  1506.   vect = new par[max];
  1507. }
  1508.  
  1509. /*
  1510.   Mantiene un conjunto de "par"es:
  1511.   busca cadena p en vector asociativo
  1512.   devuelve una referencia a la parte entera de su "par"
  1513.   crea un nuevo "par" si la cadena p no se encuentra
  1514. */
  1515.  
  1516. int& asoc::operator[] (char *p)
  1517. {
  1518.   register par *pp;
  1519.  
  1520.   for (pp = &vect[libre-1]; vect <= pp; pp--)
  1521.     if (strcmp (p, pp->nombre) == 0)
  1522.       return pp->valor;
  1523.  
  1524.   if (libre == max) // desbordamiento: es necesario crecer el vector
  1525.     {
  1526.       par *nvect = new par[max*2];
  1527.       for (int i = 0; i < max; i++)
  1528.         nvect[i] = vect[i];
  1529.       delete vect;
  1530.       vect = nvect;
  1531.       max *= 2;
  1532.     }
  1533.  
  1534.   pp = &vect[libre++];
  1535.   pp->nombre = new char[strlen (p) + 1];
  1536.   strcpy (pp->nombre, p);
  1537.   pp->valor = 0; // valor inicial: 0
  1538.   return pp->valor;
  1539. }
  1540.  
  1541. void asoc::imprimir_todo (void)
  1542. {
  1543.   for (int i = 0; i < libre; i++)
  1544.     cout << vect[i].nombre << ": " << vect[i].valor << "\n";
  1545. }
  1546.  
  1547. void main (void)
  1548. {
  1549.   cout << "EJEMPLO DE LA CLASE asoc\n\n";
  1550.  
  1551.   const MAX = 256; // palabra más larga
  1552.   char buf[MAX];
  1553.   asoc vect (512);
  1554.  
  1555.   while (cin >> buf)
  1556.     vect[buf]++;
  1557.   vect.imprimir_todo ();
  1558.  
  1559.   getch ();
  1560. }
  1561. ende
  1562. begine " CLASE iterador_asociat "
  1563. /*
  1564.   Este programa cuenta las ocurrencias de cada palabra leída de la entrada
  1565.   estándar. La entrada estándar es por defecto el teclado pero se puede
  1566.   redirigir el programa para que lea de un fichero.
  1567.  
  1568.   Este ejemplo hace exactamente lo mismo que el ejemplo anterior pero
  1569.   utilizando una forma más conveniente de hacerlo que el ejemplo precedente.
  1570.  
  1571.   Define la clase interador_asociat para que realice el trabajo de presentar
  1572.   los elementos del vector asociativo (clase asociat) en el mismo orden en
  1573.   el que se encuentran en dicho vector.
  1574.  
  1575.   Lo más interesante de este ejemplo es la sobrecarga del operador () que
  1576.   realiza las llamadas a las funciones. Una llamada a función, esto es, la
  1577.   notación expresion(lista_expresiones), puede ser interpretada como una
  1578.   operación binaria, y el operador de llamada () puede ser sobrecargado de
  1579.   la misma forma que los demás operadores. Una lista de argumentos para una
  1580.   función operator() es evaluada y chequeada acorde a las reglas usuales de
  1581.   paso de argumentos.
  1582. */
  1583.  
  1584. #include <iostream.h> // cout, cin
  1585. #include <conio.h>    // getch ()
  1586. #include <string.h>   // strcmp (), strlen (), strcpy ()
  1587.  
  1588. struct par_asociat // cada elemento del vector asociativo
  1589.   {
  1590.     char *nombre;
  1591.     int valor;
  1592.   };
  1593.  
  1594. class asociat // vector asociativo
  1595.   {
  1596.     friend class iterador_asociat;
  1597.  
  1598.     par_asociat *vect;
  1599.     int max;   // tamaño del vector
  1600.     int libre; // índice del primer elemento del vector no usado
  1601.  
  1602.     public:
  1603.  
  1604.     asociat (int);
  1605.     int& operator[] (char *);
  1606.   };
  1607.  
  1608. class iterador_asociat
  1609.  {
  1610.    asociat *ac; // array asociativo actual
  1611.    int i;
  1612.  
  1613.    public:
  1614.  
  1615.    iterador_asociat (asociat& a) { ac = &a; i = 0; }
  1616.    par_asociat *operator() (void) { return i < ac->libre ? &ac->vect[i++] : 0; }
  1617.  };
  1618.  
  1619. asociat::asociat (int tam)
  1620. {
  1621.   max = tam < 16 ? tam : 16;
  1622.   libre = 0;
  1623.   vect = new par_asociat[max];
  1624. }
  1625.  
  1626. /*
  1627.   Mantiene un conjunto de pares del vector asociativo ordenados:
  1628.   busca cadena p en vector asociativo
  1629.   devuelve una referencia a la parte entera de su par
  1630.   crea un nuevo par si la cadena p no se encuentra
  1631. */
  1632.  
  1633. int& asociat::operator[] (char *p)
  1634. {
  1635.   register par_asociat *pp;
  1636.  
  1637.   for (pp = &vect[libre-1]; vect <= pp; pp--)
  1638.     if (strcmp (p, pp->nombre) == 0)
  1639.       return pp->valor;
  1640.  
  1641.   if (libre == max) // desbordamiento: es necesario crecer el vector
  1642.     {
  1643.       par_asociat *nvect = new par_asociat[max*2];
  1644.       for (int i = 0; i < max; i++)
  1645.         nvect[i] = vect[i];
  1646.       delete vect;
  1647.       vect = nvect;
  1648.       max *= 2;
  1649.     }
  1650.  
  1651.   pp = &vect[libre++];
  1652.   pp->nombre = new char[strlen (p) + 1];
  1653.   strcpy (pp->nombre, p);
  1654.   pp->valor = 0; // valor inicial: 0
  1655.   return pp->valor;
  1656. }
  1657.  
  1658. void main (void)
  1659. {
  1660.   cout << "EJEMPLO DE LA CLASE iterador_asoc\n\n";
  1661.  
  1662.   const MAX = 256; // palabra más larga
  1663.   char buf[MAX];
  1664.   asociat vect (512);
  1665.  
  1666.   while (cin >> buf)
  1667.     vect[buf]++;
  1668.  
  1669.   iterador_asociat siguiente (vect);
  1670.   par_asociat *p;
  1671.  
  1672.   while ((p = siguiente ()) != 0)
  1673.     cout << p->nombre << ": " << p->valor << "\n";
  1674.  
  1675.   getch ();
  1676. }
  1677. ende
  1678. begine " CLASE fecha "
  1679. /*
  1680.   Este programa desarrolla la clase fecha y la función main() para probarla.
  1681.   La clase fecha es infinitamente mejorable pues tiene muchas deficiencias,
  1682.   no obstante, aquí se ha dado la idea base para desarrollar una clase fecha
  1683.   mucho más perfeccionada.
  1684. */
  1685.  
  1686. #include <iostream.h>  // cout
  1687. #include <conio.h>     // getch ()
  1688. #include <dos.h>       // int86 ()
  1689. #include <stdlib.h>    // atoi ()
  1690.  
  1691. class fecha
  1692.   {
  1693.     private:
  1694.  
  1695.       int dia, mes, anio;
  1696.       long num_dias;  // número de días desde 1900
  1697.       void convertir (void);
  1698.  
  1699.     public:
  1700.  
  1701.       fecha (void);
  1702.       fecha (int d, int m, int a);
  1703.       fecha (char *str);
  1704.  
  1705.       operator long () { return num_dias; }
  1706.       fecha operator+ (int num)
  1707.         { return fecha (dia + num, mes, anio); }
  1708.       fecha& operator+= (int num)
  1709.         { return *this = *this + num; }
  1710.       void ver (char *str) { cout << str << dia << '/' << mes << '/' << anio; }
  1711.   };
  1712.  
  1713. // Calcula el número de días a partir del 1/1/1900
  1714. void fecha::convertir (void)
  1715. {
  1716.   int dias_meses;
  1717.  
  1718.   num_dias = 386 * (anio - 1900);
  1719.   switch (mes)
  1720.     {
  1721.       case  1 : dias_meses =   0; break;
  1722.       case  2 : dias_meses =  31; break;
  1723.       case  3 : dias_meses =  59; break;
  1724.       case  4 : dias_meses =  90; break;
  1725.       case  5 : dias_meses = 120; break;
  1726.       case  6 : dias_meses = 151; break;
  1727.       case  7 : dias_meses = 181; break;
  1728.       case  8 : dias_meses = 212; break;
  1729.       case  9 : dias_meses = 243; break;
  1730.       case 10 : dias_meses = 273; break;
  1731.       case 11 : dias_meses = 304; break;
  1732.       case 12 : dias_meses = 334; break;
  1733.     }
  1734.   num_dias += dias_meses + dia;
  1735. }
  1736.  
  1737. // Asume fecha activa del sistema
  1738. fecha::fecha (void)
  1739. {
  1740.   union REGS r;
  1741.  
  1742.   r.h.ah = 0x2A; // obtener fecha del sistema (función 2Ah, int 21h)
  1743.   int86 (0x21, &r, &r);
  1744.   dia = r.h.dl;
  1745.   mes = r.h.dh;
  1746.   anio = r.x.cx;
  1747.   convertir ();
  1748. }
  1749.  
  1750. fecha::fecha (int d, int m, int a)
  1751. {
  1752.   dia = d;
  1753.   mes = m;
  1754.   anio = a;
  1755.   convertir ();
  1756. }
  1757.  
  1758. // str ha de tener la forma: dd/mm/aaaa
  1759. fecha::fecha (char *str)
  1760. {
  1761.   dia = atoi (str);
  1762.   while (*str++ != '/')
  1763.    ;
  1764.   mes = atoi (str);
  1765.   while (*str++ != '/')
  1766.     ;
  1767.   anio = atoi (str);
  1768.   convertir ();
  1769. }
  1770.  
  1771. void main (void)
  1772. {
  1773.   cout << "EJEMPLO DE LA CLASE fecha";
  1774.  
  1775.   cout << "\n\n*** Declarando: fecha f1, f2 (1, 4, 1993), f3 (\"5/4/1993\");";
  1776.   fecha f1, f2 (1, 4, 1993), f3 ("5/4/1993");
  1777.  
  1778.   f1.ver ("\nf1: ");
  1779.   f2.ver ("\nf2: ");
  1780.   f3.ver ("\nf3: ");
  1781.  
  1782.   cout << "\n\n*** Ejecutando f3 - f2 para calcular diferencia de días.";
  1783.   cout << "\nNúmero de días entre ";
  1784.   f3.ver ("");
  1785.   cout << " y ";
  1786.   f2.ver ("");
  1787.   cout << ": " << f3 - f2;
  1788.  
  1789.   cout << "\n\n*** Ejecutando f2 += 3 para sumarle 3 días a la fecha f2.";
  1790.   f2 += 3;
  1791.   f2.ver ("\nf2: ");
  1792.  
  1793.   getch ();
  1794. }
  1795. ende
  1796. end
  1797.  
  1798. ; LECCION 6
  1799. begin
  1800. begine " CLASE vector_ind "
  1801. /*
  1802.   En este ejemplo se implementa la clase vector_ind. La función main()
  1803.   prueba esta clase.
  1804.  
  1805.   La clase vector implementa un vector de enteros en el se chequea el rango
  1806.   cada vez que se accede al vector para asegurar que no accedamos a un
  1807.   elemento inexistente. Además, sobrecarga algunos operadores para realizar
  1808.   determinadas operaciones aritméticas y de asignación con los elementos de
  1809.   los vectores.
  1810.  
  1811.   La clase vector se implementó previamente, con el nombre de vect, en uno
  1812.   de los ejemplos de la lección anterior. En este caso, la clase vect la
  1813.   hemos hecho clase base de la clase vector_ind, con la cual podemos traba-
  1814.   jar con arrays seguros (se chequea rango) en los cuales especificamos
  1815.   índice mínimo y máximo del array.
  1816. */
  1817.  
  1818. #include <iostream.h> // cout, cin
  1819. #include <stdlib.h>   // exit()
  1820. #include <conio.h>    // getch()
  1821.  
  1822. // Un tipo seguro de array: chequea rangos
  1823. class vector
  1824.   {
  1825.     int *p;                             // puntero base
  1826.     int tam;                            // número de elementos
  1827.  
  1828.     public:
  1829.  
  1830.     // constructores y destructor
  1831.     vector (void);                        // crea un array de 10 elementos
  1832.     vector (int n);                       // crea un array de n elementos
  1833.     vector (vector& v);                     // inicialización por vector
  1834.     vector (int a[], int n);              // inicialización por array
  1835.     ~vector (void) { delete p; }
  1836.  
  1837.     // otras funciones miembros
  1838.     int is (void) { return (tam - 1); } // índice superior
  1839.     int& operator [] (int i);
  1840.  
  1841.     void imprimir (const char *mensaje);
  1842.     void error (const char *mensaje);
  1843.   };
  1844.  
  1845. // Un array con índices inferior y superior, esto es, con índice mínimo y
  1846. // con índice máximo
  1847. class vector_ind : public vector
  1848.   {
  1849.     int ind_inf, ind_sup; // índices inferior y superior del vector
  1850.  
  1851.     public:
  1852.  
  1853.     vector_ind (void);
  1854.     vector_ind (int ii, int is);
  1855.  
  1856.     int& operator[] (int i);
  1857.  
  1858.     int ii (void) { return (ind_inf); } // devuelve índice inferior
  1859.     int is (void) { return (ind_sup); } // devuelve índice superior
  1860.  
  1861.     void error (const char *mensaje);
  1862.   };
  1863.  
  1864. vector::vector (void)
  1865. {
  1866.   p = new int[tam = 10];
  1867. }
  1868.  
  1869. vector::vector (int n)
  1870. {
  1871.   if (n < 0)
  1872.     error ("Tamaño ilegal de vector.");
  1873.   p = new int[tam = n];
  1874. }
  1875.  
  1876. vector::vector (int a[], int n)
  1877. {
  1878.   if (n < 0)
  1879.     error ("Tamaño ilegal de vector.");
  1880.   p = new int[tam = n];
  1881.   for (int i = 0; i < tam; ++i)
  1882.     p[i] = a[i];
  1883. }
  1884.  
  1885. vector::vector (vector& v)
  1886. {
  1887.   p = new int[tam = v.tam];
  1888.   for (int i = 0; i < tam; ++i)
  1889.     p[i] = v.p[i];
  1890. }
  1891.  
  1892. int& vector::operator [] (int i)
  1893. {
  1894.   if (i < 0 || i > is ())
  1895.     error ("Indice fuera de rango.");
  1896.   return p[i];
  1897. }
  1898.  
  1899. void vector::imprimir (const char *mensaje)
  1900. {
  1901.   cout << '\n' << mensaje << ": [";
  1902.   for (register int i = 0; i < tam; i++)
  1903.     cout << ' ' << p[i];
  1904.   cout << " ]";
  1905. }
  1906.  
  1907. void vector::error (const char *msj)
  1908. {
  1909.   cerr << "\nError en clase vector: " << msj << "\n";
  1910.   getch ();
  1911.   exit (1);
  1912. }
  1913.  
  1914. vector_ind::vector_ind (void) : vector (10)
  1915. {
  1916.   ind_inf = 0;
  1917.   ind_sup = 9;
  1918. }
  1919.  
  1920. vector_ind::vector_ind (int ii, int is): vector (is - ii + 1)
  1921. {
  1922.   ind_inf = ii;
  1923.   ind_sup = is;
  1924. }
  1925.  
  1926. int& vector_ind::operator[] (int i)
  1927. {
  1928.   if (i < ind_inf || i > ind_sup)
  1929.     error ("Indice fuera de rango.");
  1930.   return (vector::operator[] (i - ind_inf));
  1931. }
  1932.  
  1933. void vector_ind::error (const char *msj)
  1934. {
  1935.   cerr << "\nError en clase vector_ind: " << msj << "\n";
  1936.   getch ();
  1937.   exit (1);
  1938. }
  1939.  
  1940. void main (void)
  1941. {
  1942.   cout << "EJEMPLO DE LA CLASE vector_ind\n";
  1943.  
  1944.   vector_ind x (-2, 7), y (4, 8), z;
  1945.   register int i;
  1946.  
  1947.   for (i = -2; i <= 7; i++)
  1948.     x[i] = i;
  1949.   for (i = 4; i <= 8; i++)
  1950.     y[i] = i;
  1951.   for (i = 0; i <= 9; i++)
  1952.     z[i] = i;
  1953.  
  1954.   x.imprimir ("\nVector x");
  1955.   y.imprimir ("\nVector y");
  1956.   z.imprimir ("\nVector z");
  1957.  
  1958.   cout << "\n";
  1959.   cout << "\nIntentando acceder a x[8] " << x[8];
  1960.  
  1961.   getch ();
  1962. }
  1963. ende
  1964. end
  1965.  
  1966. ; LECCION 7
  1967. begin
  1968. begine " CLASES PARA CONTADORES "
  1969. /*
  1970.   Este programa muestra diversas clases cuyos objetos son utilizados como
  1971.   contadores.
  1972.  
  1973.   Primero se ha diseñado la clase contador, una vez hecho esto, es fácil
  1974.   añadirle mejoras creando clases derivadas de ésta sin tener que modificar
  1975.   para nada la clase base.
  1976.  
  1977.   Las clase base contador ha de ser virtual para las clases derivadas
  1978.   contador_con_valor_maximo y contador_con_valor_minimo para que no haya
  1979.   problemas al hacer estas dos clases derivadas de la clase contador,
  1980.   clase base de la clase contador_con_rango.
  1981.  
  1982.   La función main() se limita a probar las clases diseñadas para comprobar
  1983.   la manera en que funcionan dichas clases.
  1984. */
  1985.  
  1986. #include <iostream.h> // cout
  1987. #include <limits.h>   // INT_MAX, INT_MIN
  1988. #include <conio.h>    // getch ()
  1989.  
  1990. class contador
  1991.   {
  1992.     private:
  1993.  
  1994.       int valor;
  1995.  
  1996.     public:
  1997.  
  1998.       contador (int valor_inicial = 0)
  1999.       {
  2000.         valor = valor_inicial;
  2001.       }
  2002.  
  2003.       void inc (void)
  2004.       {
  2005.         if (valor < INT_MAX)
  2006.           valor++;
  2007.       }
  2008.  
  2009.       void dec (void)
  2010.       {
  2011.         if (valor > INT_MIN)
  2012.           valor--;
  2013.       }
  2014.  
  2015.       void asig (int val)
  2016.       {
  2017.         valor = val;
  2018.       }
  2019.  
  2020.       int val (void)
  2021.       {
  2022.         return valor;
  2023.       }
  2024.   };
  2025.  
  2026. class contador_con_valor_maximo : virtual public contador
  2027.   {
  2028.     private:
  2029.  
  2030.       int valor_maximo;
  2031.  
  2032.     public:
  2033.  
  2034.       contador_con_valor_maximo (int valmax) : contador ()
  2035.       {
  2036.         valor_maximo = valmax;
  2037.       }
  2038.  
  2039.       void inc (void)
  2040.       {
  2041.         if (val () < valor_maximo)
  2042.           contador::inc ();
  2043.       }
  2044.   };
  2045.  
  2046. class contador_con_valor_minimo : virtual public contador
  2047.   {
  2048.     private:
  2049.  
  2050.       int valor_minimo;
  2051.  
  2052.     public:
  2053.  
  2054.       contador_con_valor_minimo (int valmin) : contador ()
  2055.       {
  2056.         asig (valor_minimo = valmin);
  2057.       }
  2058.  
  2059.       void dec (void)
  2060.       {
  2061.         if (val () > valor_minimo)
  2062.           contador::dec ();
  2063.       }
  2064.   };
  2065.  
  2066. class contador_con_rango : public contador_con_valor_maximo,
  2067.                            public contador_con_valor_minimo
  2068.   {
  2069.     public:
  2070.  
  2071.       contador_con_rango (int valmin, int valmax) :
  2072.         contador_con_valor_minimo (valmin),
  2073.         contador_con_valor_maximo (valmax)
  2074.       { }
  2075.   };
  2076.  
  2077. void main (void)
  2078. {
  2079.   contador c;
  2080.   contador_con_valor_maximo cmaximo (10);
  2081.   contador_con_valor_minimo cminimo (5);
  2082.   contador_con_rango crango (-5, 5);
  2083.  
  2084.   register int i;
  2085.  
  2086.   cout << "EJEMPLO SOBRE LAS CLASES DE CONTADORES.";
  2087.  
  2088.   c.asig (INT_MAX - 3);
  2089.   cout << "\n\nProbando objeto de tipo contador: " << c.val ();
  2090.   for (i = 1; i <= 5 ; i++)
  2091.     {
  2092.       c.inc ();
  2093.       cout << ' ' << c.val ();
  2094.     }
  2095.  
  2096.   cmaximo.dec ();
  2097.   cout << "\n\nProbando objeto de tipo contador_con_valor_maximo: " << cmaximo.val ();
  2098.   for (i = 0; i <= 7; i++)
  2099.     {
  2100.       cmaximo.inc ();
  2101.       cout << ' ' << cmaximo.val ();
  2102.     }
  2103.  
  2104.   cminimo.asig (10);
  2105.   cout << "\n\nProbando objeto de tipo contador_con_valor_minimo: " << cminimo.val ();
  2106.   for (i = cminimo.val (); i >= 3; i--)
  2107.     {
  2108.       cminimo.dec ();
  2109.       cout << ' ' << cminimo.val ();
  2110.     }
  2111.  
  2112.   cout << "\n\nProbando objeto de tipo contador_con_rango:";
  2113.   for (i = -5; i <= 5; i++, crango.inc ())
  2114.     {
  2115.       cout << ' ' << crango.val ();
  2116.     }
  2117.  
  2118.   getch ();
  2119. }
  2120. ende
  2121. end
  2122.  
  2123. ; LECCION 8
  2124. begin
  2125. begine " CLASE fraccion "
  2126. /*
  2127.   Este ejemplo implementa la clase fraccion y una función main() para probar
  2128.   esta clase.
  2129.   La clase fraccion nos permite trabajar con fracciones. Las fracciones son
  2130.   números reales en la forma: numerador/denominador.
  2131.   Observad la sobrecarga de los operadores << y >>. Sobrecargar estos opera-
  2132.   dores es más cómodo que implementar métodos para imprimir como podría ser:
  2133.   void fraccion::imprimir (void).
  2134. */
  2135.  
  2136. #include <iostream.h> // cout, << sobrecargado
  2137. #include <stdlib.h>   // abs ()
  2138. #include <conio.h>    // getch ()
  2139.  
  2140. class fraccion
  2141. {
  2142.   private:
  2143.  
  2144.     long numerador, denominador;
  2145.  
  2146.   public:
  2147.  
  2148.     fraccion (long num = 0, long den = 1) // constructor
  2149.     {
  2150.       numerador = num;
  2151.       denominador = den;
  2152.       simplificar (*this);
  2153.     }
  2154.  
  2155.     // operadores aritméticos binarios
  2156.  
  2157.     fraccion operator+ (fraccion frac)
  2158.     {
  2159.       long lmcm = mcm (denominador, frac.denominador);
  2160.       fraccion fr = fraccion (lmcm / denominador * numerador +
  2161.                               lmcm / frac.denominador * frac.numerador, lmcm);
  2162.       simplificar (fr);
  2163.       return (fr);
  2164.     }
  2165.  
  2166.     fraccion operator- (fraccion frac)
  2167.     {
  2168.       return (operator+ (-frac));
  2169.     }
  2170.  
  2171.     fraccion operator* (fraccion frac)
  2172.     {
  2173.       fraccion fr = fraccion (numerador * frac.numerador,
  2174.                               denominador * frac.denominador);
  2175.       simplificar (fr);
  2176.       return (fr);
  2177.     }
  2178.  
  2179.     fraccion operator/ (fraccion frac)
  2180.     {
  2181.       return (operator* (fraccion (frac.denominador, frac.numerador)));
  2182.     }
  2183.  
  2184.     // operadores de asignación binarios
  2185.  
  2186.     fraccion operator+= (fraccion frac)
  2187.     {
  2188.       return (*this = *this + frac);
  2189.     }
  2190.  
  2191.     fraccion operator-= (fraccion frac)
  2192.     {
  2193.       return (*this = *this - frac);
  2194.     }
  2195.  
  2196.     fraccion operator*= (fraccion frac)
  2197.     {
  2198.       return (*this = *this * frac);
  2199.     }
  2200.  
  2201.     fraccion operator/= (fraccion frac)
  2202.     {
  2203.       return (*this = *this / frac);
  2204.     }
  2205.  
  2206.     // operadores aritméticos unarios
  2207.  
  2208.     fraccion operator+ (void)
  2209.     {
  2210.       return (*this);
  2211.     }
  2212.  
  2213.     fraccion operator- (void)
  2214.     {
  2215.       return (fraccion (-numerador, denominador));
  2216.     }
  2217.  
  2218.     // operadores de asignación unarios
  2219.  
  2220.     fraccion operator++ (void)
  2221.     {
  2222.       return (*this += 1);
  2223.     }
  2224.  
  2225.     fraccion operator-- (void)
  2226.     {
  2227.       return (*this -= 1);
  2228.     }
  2229.  
  2230.     // otros operadores
  2231.  
  2232.     operator double ()
  2233.     {
  2234.       return ((double) numerador / denominador);
  2235.     }
  2236.  
  2237.     friend ostream& operator<< (ostream &out, fraccion frac)
  2238.     {
  2239.       return (frac.denominador == 1 ?
  2240.               out << frac.numerador :
  2241.               out << frac.numerador << '/' << frac.denominador);
  2242.     }
  2243.  
  2244.     friend istream& operator>> (istream &in, fraccion& frac)
  2245.     {
  2246.       return (in >> frac.numerador >> '/' >> frac.denominador);
  2247.     }
  2248.  
  2249.   private:
  2250.  
  2251.     void simplificar (fraccion& frac);
  2252.  
  2253.     long mcd (long num1, long num2);
  2254.  
  2255.     long mcm (long num1, long num2) // devuelve mínimo común múltiplo
  2256.     {
  2257.       return (num1 / mcd (num1, num2) * num2);
  2258.     }
  2259. };
  2260.  
  2261. //  En el interior de esta clase no se puede llamar al constructor fraccion,
  2262. //  ya que se produciría un bucle infinito
  2263. void fraccion::simplificar (fraccion& frac)
  2264. {
  2265.   if (frac.numerador == 0)
  2266.     {
  2267.       frac.numerador = 0;
  2268.       frac.denominador = 1;
  2269.     }
  2270.   else
  2271.     {
  2272.       long lmcd = mcd (frac.numerador, frac.denominador);
  2273.       frac.numerador = frac.numerador / lmcd;
  2274.       frac.denominador = frac.denominador / lmcd;
  2275.     }
  2276.  
  2277.   if (frac.numerador < 0 && frac.denominador < 0)
  2278.     {
  2279.       frac.numerador = -frac.numerador;
  2280.       frac.denominador = -frac.denominador;
  2281.     }
  2282.   else if (frac.numerador < 0 || frac.denominador < 0)
  2283.     {
  2284.       frac.numerador = - abs (frac.numerador);
  2285.       frac.denominador = abs (frac.denominador);
  2286.     }
  2287. }
  2288.  
  2289. // Devuelve el máximo común divisor de dos números
  2290. long fraccion::mcd (long num1, long num2)
  2291. {
  2292.   num1 = abs (num1);
  2293.   num2 = abs (num2);
  2294.  
  2295.   while (num1 != num2)
  2296.     if (num1 > num2)
  2297.       num1 -= num2;
  2298.     else
  2299.       num2 -= num1;
  2300.  
  2301.   return (num1);
  2302. }
  2303.  
  2304. inline void imprimir_operacion (const char *operacion)
  2305. {
  2306.   cout << "\n*** Ejecutando: " << operacion;
  2307. }
  2308.  
  2309. inline void imprimir_variables (fraccion x, fraccion y, double z)
  2310. {
  2311.   cout << "\nx = " << x << "\ny = " << y << "\nz = " << z;
  2312. }
  2313.  
  2314. void main (void)
  2315. {
  2316.   cout << "EJEMPLO DE LA CLASE fraccion\n";
  2317.  
  2318.   cout << "\n*** Declarando: fraccion x = 4 / 2, y (3, 9); double z = -x;";
  2319.   fraccion x = 4 / 2, y (3, 9); double z = -x;
  2320.   imprimir_variables (x, y, z);
  2321.  
  2322.   imprimir_operacion ("z = x = --y - 2;");
  2323.   z = x = --y - 2;
  2324.   imprimir_variables (x, y, z);
  2325.  
  2326.   imprimir_operacion ("x = fraccion(1,3) - 5, y = fraccion(10,-5) + fraccion(1,5) * 3;");
  2327.   x = fraccion (1, 3) - 5, y = fraccion (10, -5) + fraccion (1, 5) * 3;
  2328.   imprimir_variables (x, y, z);
  2329.  
  2330.   imprimir_operacion ("z = x - (y == 5), z = long (z), x += x -= z, y = x / z;");
  2331.   z = x - (y == 5), z = long (z), x += x -= z, y = x / z;
  2332.   imprimir_variables (x, y, z);
  2333.  
  2334.   imprimir_operacion ("z *= (x == y) < (z != y), y /= x;");
  2335.   z *= (x == y) < (z != y), y /= x;
  2336.   imprimir_variables (x, y, z);
  2337.  
  2338.   imprimir_operacion ("cout << \"\\nIntroduce x en la forma n/d: \", cin >> x;");
  2339.   cout << "\nIntroduce x en la forma n/d: ", cin >> x;
  2340.   cout << "x = " << x;
  2341.  
  2342.   getch ();
  2343. }
  2344. ende
  2345. begine " PROGRAMA COPIAR "
  2346. /*
  2347.   Este programa copia un fichero en otro. El fichero fuente debe existir, en
  2348.   caso de no ser así, se produce un error en la apertura de este fichero. Si
  2349.   el fichero destino no existe, se crea uno nuevo si es posible, si por el
  2350.   contrario ya existe, se sobreescribirá, es decir, se perderá la información
  2351.   que contega.
  2352.  
  2353.   Se ofrecen dos versiones. La segunda versión, que es la que se ejecuta,
  2354.   se suministra para poder ejecutar este programa desde el tutor. La segunda
  2355.   versión, que es la que está dentro del comentario, se suministra por si el
  2356.   usuario desea copiar este ejemplo a un fichero (se recomienda llamarlo
  2357.   COPIAR para que el nombre del programa ejecutable sea COPIAR) y convertirlo
  2358.   en un programa ejecutable; en esta forma es más útil leyendo los nombres de
  2359.   los ficheros desde la línea de órdenes del sistema operativo; la sintaxis
  2360.   es: COPIAR fichero_fuente fichero_destino.
  2361. */
  2362.  
  2363. #include <iostream.h> // para cerr, cout
  2364. #include <stdlib.h>  // para exit ()
  2365. #include <fstream.h>  // para ifstream, ofstream
  2366.  
  2367. /*
  2368. void main (int argc, char* argv[])
  2369. {
  2370.   if (argc != 3)
  2371.     {
  2372.       cerr << "USO: COPIAR fichero1 fichero2\n";
  2373.       exit (-1);
  2374.     }
  2375.  
  2376.   ifstream fuente;
  2377.   ofstream destino;
  2378.  
  2379.   fuente.open (argv[1]);
  2380.   if (! fuente)
  2381.     {
  2382.       cerr << "No se puede abrir el fichero fuente " << argv[1]
  2383.            << " para lectura.\n";
  2384.       exit (-1);
  2385.     }
  2386.  
  2387.   destino.open (argv[2]);
  2388.   if (! destino)
  2389.     {
  2390.       cerr << "No se puede abrir el fichero destino " << argv[2]
  2391.            << " para escritura.\n";
  2392.       exit (-1);
  2393.     }
  2394.  
  2395.   char ch;
  2396.  
  2397.   while (destino && fuente.get (ch))
  2398.     destino.put (ch);
  2399.  
  2400.   cout << "Copia completada.\n";
  2401.  
  2402.   fuente.close ();
  2403.   destino.close ();
  2404. }
  2405. */
  2406.  
  2407. void main (void)
  2408. {
  2409.   cout << "\nCOPIAR fichero_fuente en fichero_destino.\n";
  2410.  
  2411.   const int longitud_maxima_fichero = 128;
  2412.   typedef char nombre_fichero [longitud_maxima_fichero];
  2413.   nombre_fichero nombre_fichero_fuente, nombre_fichero_destino;
  2414.  
  2415.   cout << "Introduce fichero fuente: ";
  2416.   cin.getline (nombre_fichero_fuente, longitud_maxima_fichero);
  2417.   cout << "Introduce fichero destino: ";
  2418.   cin.getline (nombre_fichero_destino, longitud_maxima_fichero);
  2419.  
  2420.   ifstream fuente;
  2421.   ofstream destino;
  2422.  
  2423.   fuente.open (nombre_fichero_fuente);
  2424.   if (! fuente)
  2425.     {
  2426.       cerr << "No se puede abrir el fichero fuente " << nombre_fichero_fuente
  2427.            << " para lectura.\n";
  2428.       exit (-1);
  2429.     }
  2430.  
  2431.   destino.open (nombre_fichero_destino);
  2432.   if (! destino)
  2433.     {
  2434.       cerr << "No se puede abrir el fichero destino " << nombre_fichero_destino
  2435.            << " para escritura.\n";
  2436.       exit (-1);
  2437.     }
  2438.  
  2439.   char ch;
  2440.  
  2441.   while (destino && fuente.get (ch))
  2442.     destino.put (ch);
  2443.  
  2444.   cout << "Copia completada.\n";
  2445.  
  2446.   fuente.close ();
  2447.   destino.close ();
  2448. }
  2449. ende
  2450. begine " CLASE string "
  2451. /*
  2452.   Este programa implementa la clase string y la función main para probarla.
  2453.   Esta clase cuenta las referencias a una cadena de caracteres para minimizar
  2454.   la copia y el espacio utilizado. La copia de clases es muy utilizada en
  2455.   objetos temporales tales como argumentos por valor u objetos devueltos por
  2456.   funciones.
  2457. */
  2458.  
  2459. #include <iostream.h> // cout, cin, cerr
  2460. #include <conio.h>    // getch ()
  2461. #include <string.h>   // strlen (), strcpy ()
  2462. #include <stdlib.h>   // exit ()
  2463.  
  2464. class string
  2465.   {
  2466.     struct sstring
  2467.       {
  2468.         char *s; // puntero a los datos
  2469.         int n;   // contador de referencias
  2470.       };
  2471.  
  2472.     sstring *p;
  2473.  
  2474.     public:
  2475.  
  2476.     string (char *);     // string x = "abc"
  2477.     string (void);       // string x;
  2478.     string (string &);   // string x = string ...
  2479.     string& operator= (char *);
  2480.     string& operator= (string &);
  2481.     ~string ();
  2482.     char& operator[] (int i);
  2483.  
  2484.     friend ostream& operator<< (ostream&, string&);
  2485.     friend istream& operator>> (istream&, string&);
  2486.  
  2487.     friend int operator== (string &x, char *s)
  2488.       { return strcmp (x.p->s, s) == 0; }
  2489.  
  2490.     friend int operator== (string &x, string &y)
  2491.       { return strcmp (x.p->s, y.p->s) == 0; }
  2492.  
  2493.     friend int operator!= (string &x, char *s)
  2494.       { return strcmp (x.p->s, s) != 0; }
  2495.  
  2496.     friend int operator!= (string &x, string &y)
  2497.       { return strcmp (x.p->s, y.p->s) != 0; }
  2498.   };
  2499.  
  2500. string::string (void)
  2501. {
  2502.   p = new sstring;
  2503.   p->s = 0;
  2504.   p->n = 1;
  2505. }
  2506.  
  2507. string::string (char *s)
  2508. {
  2509.   p = new sstring;
  2510.   p->s = new char [strlen (s) + 1];
  2511.   strcpy (p->s, s);
  2512.   p->n = 1;
  2513. }
  2514.  
  2515. string::string (string& x)
  2516. {
  2517.   x.p->n++;
  2518.   p = x.p;
  2519. }
  2520.  
  2521. string::~string ()
  2522. {
  2523.   if (--p->n == 0)
  2524.     {
  2525.       delete p->s;
  2526.       delete p;
  2527.     }
  2528. }
  2529.  
  2530. string& string::operator= (char *s)
  2531. {
  2532.   if (p->n > 1) // se desconecta
  2533.     {
  2534.       p->n--;
  2535.       p = new sstring;
  2536.     }
  2537.   else if (p->n == 1)
  2538.     delete p->s;
  2539.  
  2540.   p->s = new char [strlen (s) + 1];
  2541.   strcpy (p->s, s);
  2542.   p->n = 1;
  2543.   return *this;
  2544. }
  2545.  
  2546. string& string::operator= (string& x)
  2547. {
  2548.   x.p->n++;
  2549.   if (--p->n == 0)
  2550.     {
  2551.       delete p->s;
  2552.       delete p;
  2553.     }
  2554.   p = x.p;
  2555.   return *this;
  2556. }
  2557.  
  2558. ostream& operator<< (ostream& s, string& x)
  2559. {
  2560.   return s << x.p->s;
  2561. }
  2562.  
  2563. istream& operator>> (istream& s, string& x)
  2564. {
  2565.   const int tam = 256;
  2566.   char buf[tam];
  2567.   s.getline (buf, 256);
  2568.   x = buf;
  2569.   return s;
  2570. }
  2571.  
  2572. void error_en_string (char *p)
  2573. {
  2574.   cerr << "\nError: " << p << "\n";
  2575.   getch ();
  2576.   exit (1);
  2577. }
  2578.  
  2579. char& string::operator[] (int i)
  2580. {
  2581.   if (i < 0 || strlen (p->s) < i)
  2582.     error_en_string ("índice fuera de rango");
  2583.   return p->s[i];
  2584. }
  2585.  
  2586. void main (void)
  2587. {
  2588.   cout << "EJEMPLO DE LA CLASE string\n";
  2589.  
  2590.   cout << "\nDeclarando: string s1, s2, s3;\n";
  2591.   string s1, s2, s3;
  2592.  
  2593.   cout << "\nIntroduce s1: ";
  2594.   cin >> s1;
  2595.  
  2596.   cout << "\nIntroduce s2: ";
  2597.   cin >> s2;
  2598.  
  2599.   cout << "\nAsignando: s3 = s1;   s3: " << (s3 = s1) << "\n";
  2600.  
  2601.   cout << "\nComparando: s1 != s2: " << (s1 != s2) << "\n";
  2602.   cout << "\nComparando: s1 == s3: " << (s1 == s3) << "\n";
  2603.  
  2604.   cout << "\nIndexando: s2[5]: " << s2[5] << "\n";
  2605.  
  2606.   getch ();
  2607. }
  2608. ende
  2609. begine " CONTADOR DE PALABRAS "
  2610. /*
  2611.   Este programa cuenta el número de palabras contenidas en un fichero.
  2612.  
  2613.   Se ofrecen dos versiones. La segunda versión, que es la que se ejecuta,
  2614.   se suministra para poder ejecutar este programa desde el tutor. La segunda
  2615.   versión, que es la que está dentro del comentario, se suministra por si el
  2616.   usuario desea copiar este ejemplo a un fichero y convertirlo en un programa
  2617.   ejecutable; en esta forma es más útil leyendo el nombre del fichero desde
  2618.   la línea de órdenes del sistema operativo.
  2619.  
  2620.   En ambos casos, si se introduce como nombre de fichero el nombre CON, ya
  2621.   sea en minúsculas o en mayúsculas, lee de consola, esto es, de teclado.
  2622. */
  2623.  
  2624.  
  2625. #include <iostream.h> // cerr, cout
  2626. #include <fstream.h>  // ifstream
  2627. #include <stdlib.h>   // exit ()
  2628. #include <ctype.h>    // isspace ()
  2629.  
  2630. /*
  2631. void main (int argc, char *argv[])
  2632. {
  2633.   if (argc != 2)
  2634.     {
  2635.       cerr << "USO: nombre_programa nombre_fichero\n";
  2636.       exit (-1);
  2637.     }
  2638.  
  2639.   ifstream fich (argv[1]);
  2640.   if (! fich)
  2641.     {
  2642.       cerr << "Error al intentar abrir el fichero " << argv[1] << "\n";
  2643.       exit (-1);
  2644.     }
  2645.  
  2646.   int cont_palabras = 0;
  2647.   const int longmaxpal = 256;
  2648.   char palabra[longmaxpal];
  2649.  
  2650.   do
  2651.     {
  2652.       fich >> palabra;
  2653.       if (*palabra) // if necesario por si el fichero no contiene ninguna palabra
  2654.         ++cont_palabras;
  2655.     } while (fich.good ());
  2656.  
  2657.   cout << "En el fichero " << argv[1] << " hay " << cont_palabras
  2658.        << " palabra" << (cont_palabras == 1 ? "" : "s") << ".\n";
  2659.  
  2660.   fich.close ();
  2661. }
  2662. */
  2663.  
  2664. void main (void)
  2665. {
  2666.   cout << "CONTADOR DE PALABRAS DE UN FICHERO.\n";
  2667.  
  2668.   const int longmaxnomfich = 256;
  2669.   char nomfich [longmaxnomfich];
  2670.  
  2671.   cout << "Introduce nombre de fichero: ";
  2672.   cin >> nomfich;
  2673.  
  2674.   ifstream fich (nomfich);
  2675.   if (! fich)
  2676.     {
  2677.       cerr << "Error al intentar abrir el fichero " << nomfich << "\n";
  2678.       exit (-1);
  2679.     }
  2680.  
  2681.   int cont_palabras = 0;
  2682.   const int longmaxpal = 256;
  2683.   char palabra[longmaxpal];
  2684.  
  2685.   do
  2686.     {
  2687.       fich >> palabra;
  2688.       if (*palabra) // if necesario por si el fichero no contiene ninguna palabra
  2689.         ++cont_palabras;
  2690.     } while (fich.good ());
  2691.  
  2692.   cout << "En el fichero " << nomfich << " hay " << cont_palabras
  2693.        << " palabra" << (cont_palabras == 1 ? "" : "s") << ".\n";
  2694.  
  2695.   fich.close ();
  2696. }
  2697. ende
  2698. end
  2699.